package study_2;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

/**
 * 本Demo必须使用32位Java虚拟机才能看到非原子操作的效果。
 * 运行本Demo时也可以执行虚拟机参数“-client”
 */
public class Thread_2_3 implements Runnable {
    static long value = 0;
    private final long valueToSet;

    public Thread_2_3(long valueToSet){
        this.valueToSet = valueToSet;
    }

    public static void main(String[] args){
        //线程updateThread1将data更新为0
        Thread updateThread1 = new Thread(new Thread_2_3(0L));
        //线程 updateThread2将data更新为-1
        Thread updateThread2 = new Thread(new Thread_2_3(-1L));

        PrintStream ps = new PrintStream(new OutputStream() {
            @Override
            public void write(int b) throws IOException {
                //不实际进行输出
            }
        });

        updateThread1.start();
        updateThread2.start();

        //共享变量value的快照（即瞬间值）
        long snapshot;
        //这个问题呆呆的我看了好久才明白作者的意图，当该操作为非原子性时，可能snapshot的值既不为0，也不为-1，此时就不会跳转到循环中，只有32位会出现这种情况
        while(0==(snapshot = value) || -1 == snapshot){
            /**
             * 这里，我们将“snapshot = value”放在循环内是为了不断地读取共享变量value的值。
             * 而service运行模式的Java虚拟机（的JIT编译器）在生成这段代码对应的机器码的时候，
             * 可能会进行循环优化（循环不变表达式外提）而将“snapshot = value”对应的机器码
             * 放在这个循环语句之外，这就使我们无法重复读取value的值。
             * 下面的输出语句并不是为了输出数据，而是为了防止JIT编译器做“循环不变表达式外提”这种优化
             * 或者，将以下语句注释掉，以client模式运行本Demo也可以达到同样的效果
             * 防止“循环不变表达式外提”优化。
             * 循环不变表达式外提（Loop-invariant code motion);
             * http://www.compileroptmizations.com/category/hoisting.htm
             */
//            System.out.println(snapshot);
//            ps.print(snapshot);
        }

        System.err.printf("Unexpected data: %d(0x%16x)", snapshot, snapshot);
        ps.close();
        System.exit(0);
    }
    public void run(){
        for (;;){
            value = valueToSet;
        }
    }
}
